using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using NUnit.Framework;

namespace Drill.Core.Utilities
{
    [TestFixture]
    public class AssemblyUtilityTests
    {
        [Category("IntegrationTest")]
        [Test]
        [TestCaseSource("TestCasesForEnsureAssemblyIsLoaded")]
        public bool EnsureAssemblyIsLoaded(AssemblyName assemblyName)
        {
            Assembly assembly = AssemblyUtility.EnsureAssemblyIsLoaded(assemblyName);

            return (null != assembly);
        }

        public static IEnumerable<TestCaseData> TestCasesForEnsureAssemblyIsLoaded
        {
            get
            {
                yield return new TestCaseData(null).Throws(typeof(ArgumentNullException));
                yield return new TestCaseData(new AssemblyName("FakeAssemblyNameUsedForTesting")).Throws(typeof(FileNotFoundException));
                yield return new TestCaseData(new AssemblyName("mscorlib")).Returns(true);
				yield return new TestCaseData(new AssemblyName("Drill.DrillBits.Unity")).Returns(true);
            }
        }

        [Category("IntegrationTest")]
        [Test]
        [TestCaseSource("TestCasesForFindLoadedAssembly")]
        public bool FindLoadedAssembly(AssemblyName assemblyName, AppDomain domain)
        {
            Assembly assembly = AssemblyUtility.FindLoadedAssembly(assemblyName, domain);

            return (null != assembly);
        }

        public static IEnumerable<TestCaseData> TestCasesForFindLoadedAssembly
        {
            get
            {
                AppDomain currentAppDomain = AppDomain.CurrentDomain;

                yield return new TestCaseData(null, currentAppDomain).Throws(typeof(ArgumentNullException));
                yield return new TestCaseData(new AssemblyName("FakeAssemblyNameUsedForTesting"), currentAppDomain).Returns(false);
                yield return new TestCaseData(new AssemblyName("mscorlib"), null).Throws(typeof(ArgumentNullException));
                yield return new TestCaseData(new AssemblyName("mscorlib"), currentAppDomain).Returns(true);
            }
        }

        [Category("UnitTest")]
        [Test]
        [TestCaseSource("TestCasesForTrySplitAssemblyQualifiedTypeNameOverload1")]
        public bool TrySplitAssemblyQualifiedTypeNameOverload1(string assemblyQualifiedTypeName)
        {
            string assemblyName;
            string typeName;

            bool success = AssemblyUtility.TrySplitAssemblyQualifiedTypeName(assemblyQualifiedTypeName, out assemblyName, out typeName);

            return success 
                && false == string.IsNullOrEmpty(assemblyName) 
                && false == string.IsNullOrEmpty(typeName);
        }

        public static IEnumerable<TestCaseData> TestCasesForTrySplitAssemblyQualifiedTypeNameOverload1
        {
            get
            {
                yield return new TestCaseData(null).Throws(typeof(ArgumentNullException));
				yield return new TestCaseData("").Throws(typeof(ArgumentNullException));
				yield return new TestCaseData(" ").Throws(typeof(ArgumentNullException));
                yield return new TestCaseData("InvalidAssemblyQualifiedTypeNameValue").Returns(false);
                yield return new TestCaseData("TestAssemblyQualifiedTypeNameValue.SomeMadeUpTypeName,SomeMadeUpAssemblyName").Returns(true);
                yield return new TestCaseData("TestAssemblyQualifiedTypeNameValue.SomeMadeUpTypeName, SomeMadeUpAssemblyName").Returns(true);
                yield return new TestCaseData("TestAssemblyQualifiedTypeNameValue.SomeMadeUpTypeName , SomeMadeUpAssemblyName").Returns(true);
            }
        }

        [Category("UnitTest")]
        [Test]
        [TestCaseSource("TestCasesForTrySplitAssemblyQualifiedTypeNameOverload2")]
        public bool TrySplitAssemblyQualifiedTypeNameOverload2(string assemblyQualifiedTypeName)
        {
            AssemblyName assemblyName;
            string typeName;

            bool success = AssemblyUtility.TrySplitAssemblyQualifiedTypeName(assemblyQualifiedTypeName, out assemblyName, out typeName);

            return success
                && null != assemblyName
                && false == string.IsNullOrEmpty(assemblyName.FullName)
                && false == string.IsNullOrEmpty(assemblyName.Name)
                && false == string.IsNullOrEmpty(typeName);
        }

        public static IEnumerable<TestCaseData> TestCasesForTrySplitAssemblyQualifiedTypeNameOverload2
        {
            get
            {
                yield return new TestCaseData(null).Throws(typeof(ArgumentNullException));
				yield return new TestCaseData("").Throws(typeof(ArgumentNullException));
				yield return new TestCaseData(" ").Throws(typeof(ArgumentNullException));
                yield return new TestCaseData("InvalidAssemblyQualifiedTypeNameValue").Returns(false);
                yield return new TestCaseData("TestAssemblyQualifiedTypeNameValue.SomeMadeUpTypeName,SomeMadeUpAssemblyName").Returns(true);
                yield return new TestCaseData("TestAssemblyQualifiedTypeNameValue.SomeMadeUpTypeName, SomeMadeUpAssemblyName").Returns(true);
                yield return new TestCaseData("TestAssemblyQualifiedTypeNameValue.SomeMadeUpTypeName , SomeMadeUpAssemblyName").Returns(true);
            }
        }

        [Category("UnitTest")]
        [Test]
        [TestCaseSource("TestCasesForTryLoadAssemblyQualifiedTypeName")]
        public bool TryLoadAssemblyQualifiedTypeName(string assemblyQualifiedTypeName)
        {
            Assembly assembly;
            Type type;

            bool success = AssemblyUtility.TryLoadAssemblyQualifiedTypeName(assemblyQualifiedTypeName, out assembly, out type);

            return success
                && null != assembly
                && null != type;
        }

        public static IEnumerable<TestCaseData> TestCasesForTryLoadAssemblyQualifiedTypeName
        {
            get
            {
                yield return new TestCaseData(null).Throws(typeof(ArgumentNullException));
				yield return new TestCaseData("").Throws(typeof(ArgumentNullException));
				yield return new TestCaseData(" ").Throws(typeof(ArgumentNullException));
                yield return new TestCaseData("InvalidAssemblyQualifiedTypeNameValue").Returns(false);
                yield return new TestCaseData("TestAssemblyQualifiedTypeNameValue.SomeMadeUpTypeName,SomeMadeUpAssemblyName").Returns(false);
            }
        }

        [Category("IntegrationTest")]
        [Test]
        [TestCaseSource("TestCasesForTryLoadAssemblyQualifiedTypeNameIntegrationTest")]
        public bool TryLoadAssemblyQualifiedTypeNameIntegrationTest(string assemblyQualifiedTypeName)
        {
            try
            {
                DependencyResolverManager.Reset();
                Assembly assembly;
                Type type;

                bool success = AssemblyUtility.TryLoadAssemblyQualifiedTypeName(assemblyQualifiedTypeName, out assembly, out type);

                return success
                    && null != assembly
                    && null != type;
            }
            finally
            {
                DependencyResolverManager.Reset();
            }
        }

        public static IEnumerable<TestCaseData> TestCasesForTryLoadAssemblyQualifiedTypeNameIntegrationTest
        {
            get
            {
				yield return new TestCaseData("Drill.Core.DrillChuckDependencyResolver, Drill").Returns(true);
				yield return new TestCaseData("Drill.DrillBits.Unity.UnityDrillBit, Drill.DrillBits.Unity").Returns(true);
            }
        }
    }
}